using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WhsFacebook.Whs.Contracts;

namespace WhsFacebook.Whs.WhsAddin
{
    public enum AddinState
    {
        Undefined,
        WindowsServiceNotRunning,
        Ready,
    }

#region event stuff

    public class AddinStateTransitionEventArgs : EventArgs
    {
        public AddinState Previous
        {
            get; private set;
        }

        public AddinState Next
        {
            get; private set;
        }

        public AddinStateTransitionEventArgs(AddinState prev, AddinState next)
        {
            if (next == AddinState.Undefined)
                throw new ArgumentOutOfRangeException("next", "'Undefined' can never be a target state");

            this.Previous = prev;
            this.Next = next;
        }
    }

#endregion

    public sealed class AddinStateManager
    {
        #region instance
        
        private static readonly AddinStateManager _instance = new AddinStateManager();

        public static AddinStateManager Instance
        {
            get { return _instance; }
        }

        #endregion

        private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(AddinStateManager));

        public event EventHandler<AddinStateTransitionEventArgs> OnStateChanging;
        public event EventHandler<AddinStateTransitionEventArgs> OnStateChanged;

        public AddinState State
        {
            get; private set;
        }

        public void SetState(AddinState state)
        {
            if (state == AddinState.Undefined)
                throw new ArgumentOutOfRangeException("state", "'Undefined' can never be a target state");

            // no change?
            var oldState = this.State;

            if (oldState == state)
                return;

            // announce globally
            this.State = state;

            // log
            if (_log.IsDebugEnabled)
                _log.Debug("Changing state start: " + oldState + " to " + state);

            // change state
            try
            {
                // perform change
                if (this.OnStateChanging != null)
                    this.OnStateChanging(this, new AddinStateTransitionEventArgs(oldState, state));

                if (this.OnStateChanged != null)
                    this.OnStateChanged(this, new AddinStateTransitionEventArgs(oldState, state));

                // log
                if (_log.IsDebugEnabled)
                    _log.Debug("Changing state done: " + state);
            }
            catch (Exception ex)
            {
                _log.Fatal("Failed to change state from " + oldState + " to " + state, ex);

                throw;
            }
        }

        private AddinStateManager()
        {
            this.State = AddinState.Undefined;
        }

    }
}
